using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using OpenComposite.Base.Collections;
using OpenComposite.HumanActivity.Contracts.Participants;
using OpenComposite.EII.Designer.BRules;
using OpenComposite.EII.Forms;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.RepositoryUIs;

namespace OpenComposite.EII.Repository
{
	[RepositoryItem(ItemType.BRule, "repository_business_rules", "brule_id")]
	public class RepositoryBusinessRule : RepositoryItemBaseEx, IParticipant
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="RepositoryBusinessRule"/> class.
		/// </summary>
		public RepositoryBusinessRule()
			: base("brule_id", "brule_nm", "brule_desc", "brule_ntext", Resources.sNewBRule)
		{
			//_brule = null;
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="RepositoryBusinessRule"/> class.
		/// </summary>
		/// <param name="bCreateNew">if set to <c>true</c> [b create new].</param>
		public RepositoryBusinessRule(bool bCreateNew)
			: this()
		{
			if ( bCreateNew )
				this.CreateNew();
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="RepositoryBusinessRule"/> class.
		/// </summary>
		/// <param name="id">The id.</param>
		public RepositoryBusinessRule(int id)
			: this()
		{
			this.Load(id);
		}
		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the name of the business rule.
		/// </summary>
		/// <value>The name of the business rule.</value>
		public string BusinessRuleName
		{
			get { return getString("name", ""); }
			set { setValue("BusinessRuleName", "name", value); }
		}
		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public override string ImageKey
		{
			get { return "brule"; }
		}
		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public override string SelectedImageKey
		{
			get { return this.ImageKey; }
		}
		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public override Image Image
		{
			get { return Resources.png_brule; }
		}
		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public override Image SelectedImage
		{
			get { return this.Image; }
		}
		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public override ItemType RepositoryItemType
		{
			get { return ItemType.BRule; }
		}
		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public override string RepositoryItemTypeName
		{
			get { return Resources.sBRule; }
		}
		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public override string RepositoryItemTypeDescription
		{
			get { return ""; }
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public override string TableName
		{
			get { return "repository_business_rules"; }
		}
		private static List<ItemType> _LISTALLOWED = new List<ItemType>(new ItemType[] { ItemType.GenericFolder, ItemType.BRule });
		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public override List<ItemType> AllowedChildTypes
		{
			get { return _LISTALLOWED; }
		}

		/// <summary>
		/// Gets or sets the rule code.
		/// </summary>
		/// <value>The rule code.</value>
		[Editor(typeof(CodeEditorUI), typeof(UITypeEditor))]
		public string RuleCode
		{
			get { return getString("brule_code", ""); }
			set { setValue("RuleCode", "brule_code", value); }
		}
		/// <summary>
		/// Gets or sets the parameters.
		/// </summary>
		/// <value>The parameters.</value>
		public string Parameters
		{
			get { return getString("brule_parameters", ""); }
			set { setValue("Parameters", "brule_parameters", value); }
		}
		/// <summary>
		/// Gets or sets the results.
		/// </summary>
		/// <value>The results.</value>
		public string Results
		{
			get { return getString("brule_results", ""); }
			set { setValue("Results", "brule_results", value); }
		}
		/// <summary>
		/// Gets or sets the used business rules.
		/// </summary>
		/// <value>The used business rules.</value>
		public string UsedBusinessRules
		{
			get { return getString("brule_usedbrules", ""); }
			set { setValue("UsedBusinessRules", "brule_usedbrules", value); }
		}

		private BusinessRuleProperties _properties = null;
		/// <summary>
		/// Gets the extended properties.
		/// </summary>
		/// <value>The extended properties.</value>
		public BusinessRuleProperties ExtendedProperties
		{
			get
			{
				if ( _properties == null ) {
					_properties = getXmlSerializedObject<BusinessRuleProperties>("brule_xml");
					if ( _properties == null )
						_properties = new BusinessRuleProperties();
				}
				return _properties;
			}
		}
		#endregion

		#region Methods

		/// <summary>
		/// Gets the parameters.
		/// </summary>
		/// <returns></returns>
		public Dictionary<string, string> GetParameters()
		{
			if ( string.IsNullOrEmpty(this.Parameters) ) return new Dictionary<string, string>();
			Dictionary<string, string> dicParams = new Dictionary<string, string>();
			string[] strsParams = this.Parameters.Split(';');
			foreach ( string strParam in strsParams ) {
				string[] strs = strParam.Split(':');
				if ( strs.Length > 1 )
					dicParams.Add(strs[0], strs[1]);
				else
					dicParams.Add(strs[0], "string");
			}
			return dicParams;
		}
		/// <summary>
		/// Sets the parameters.
		/// </summary>
		/// <param name="dicParams">The dic params.</param>
		public void SetParameters(Dictionary<string, string> dicParams)
		{
			StringBuilder sb = new StringBuilder();
			foreach ( KeyValuePair<string, string> param in dicParams ) {
				if ( sb.Length > 0 )
					sb.Append(";");
				sb.Append(param.Key.Trim()).Append(":").Append(param.Value.Trim());
			}
			this.Parameters = sb.ToString();
		}

		/// <summary>
		/// Gets the used business rule I ds.
		/// </summary>
		/// <returns></returns>
		public List<int> GetUsedBusinessRuleIDs()
		{
			List<int> lst = new List<int>();
			string[] strs = this.UsedBusinessRules.Split(';');
			foreach ( string s in strs ) {
				int id;
				if ( int.TryParse(s, out id) )
					lst.Add(id);
			}
			return lst;
		}
		/// <summary>
		/// Sets the used business rule I ds.
		/// </summary>
		/// <param name="listIDs">The list I ds.</param>
		public void SetUsedBusinessRuleIDs(List<int> listIDs)
		{
			StringBuilder sb = new StringBuilder();
			foreach ( int id in listIDs ) {
				if ( sb.Length > 0 )
					sb.Append(";");
				sb.Append(id.ToString());
			}
			this.UsedBusinessRules = sb.ToString();
		}

		/// <summary>
		/// Gets the used rule constant I ds.
		/// </summary>
		/// <returns></returns>
		public List<int> GetUsedRuleConstantIDs()
		{
			return Global.Data.GetRuleConstantIDs(this.ID);
		}
		/// <summary>
		/// Sets the used rule constant I ds.
		/// </summary>
		/// <param name="listIDs">The list I ds.</param>
		public void SetUsedRuleConstantIDs(List<int> listIDs)
		{
			_listRuleConsts = listIDs;
		}

		/// <summary>
		/// Gets the used noun I ds.
		/// </summary>
		/// <returns></returns>
		public List<int> GetUsedNounIDs()
		{
			return Global.Data.GetNounIDsOfBusinessRule(this.ID);
		}
		/// <summary>
		/// Sets the used noun I ds.
		/// </summary>
		/// <param name="listIDs">The list I ds.</param>
		public void SetUsedNounIDs(List<int> listIDs)
		{
			_listUsedNouns = listIDs;
		}

		/// <summary>
		/// Loads the item with the specified ID.
		/// </summary>
		/// <param name="id">The ID.</param>
		/// <returns></returns>
		public override bool Load(int id)
		{
			bool ok = base.Load(id);
			//loadBusinessRule();
			return ok;
		}
		/// <summary>
		/// Reloads this instance.
		/// </summary>
		/// <returns><c>true</c> if successfully reloaded.</returns>
		public override bool Reload()
		{
			bool ok = base.Reload();
			// RE 12.12.2007: Removed, because we don't use the old business rules anymore
			//loadBusinessRule();
			return ok;
		}
		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public override bool Save()
		{
			if ( _properties != null ) {
				setXmlSerializedObject("ExtendedProperties", "brule_xml", _properties);
			}
			//saveBusinessRule();

			bool ok = base.Save();
			if ( ok && _listRuleConsts != null ) {
				Global.Data.SetRuleConstantIDs(this.ID, _listRuleConsts);
				_listRuleConsts.Clear();
				_listRuleConsts = null;
			}
			if ( ok && _listUsedNouns != null ) {
				Global.Data.SetNounIDsOfBusinessRule(this.ID, _listUsedNouns);
				_listUsedNouns.Clear();
				_listUsedNouns = null;
			}
			return ok;
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public override Icon GetIcon()
		{
			Bitmap bmp = new Bitmap(this.Image);
			bmp.MakeTransparent(Color.Magenta);
			return Icon.FromHandle(bmp.GetHicon());
		}

		#region Obsolete
		//private void loadBusinessRule()
		//{
		//    if ( this.BusinessRuleName == "" ) {
		//        _brule = null;
		//        return;
		//    }
		//    DataRow row = Global.BusinessRuleData.GetBusinessRuleDataRow(
		//        Global.CurrentUser.OrganizationID,
		//        this.BusinessRuleName);
		//    if ( row != null ) {
		//        _brule = new OpenComposite.Base.BusinessRule();
		//        _brule.ReadFromDataRow(row);
		//    } else {
		//        _brule = null;
		//    }
		//}
		//private void saveBusinessRule()
		//{
		//    bool ok = false;
		//    if ( _brule != null ) {
		//        ok = Global.BusinessRuleData.UpdateRule(_brule, Global.CurrentUser.OrganizationID);
		//        if ( ok )
		//            setValue("RuleName", "name", _brule.RuleName);



		//        // compile and save rule
		//        if ( true/*callCompilerToCheck(_brule)*/ ) {
		//            //Update the actual dll Code in the database
		//            Global.BusinessRuleData.UpdateActualDllCode(
		//                Global.BusinessRuleCompiler.UpdateActualDllCode(Global.CurrentUser.OrganizationID.ToString()),
		//                Global.CurrentUser.OrganizationID);
		//        }
		//    }
		//}
		//private bool callCompilerToCheck(OpenComposite.Base.BusinessRule rule)
		//{
		//    bool ok = false;
		//    try {
		//        string method = "public bool " + rule.RuleName + "()";
		//        string code = Global.BusinessRuleCompiler.ReadDllFramework(Global.CurrentUser.OrganizationID.ToString());
		//        string o1 = Global.BusinessRuleCompiler.UpdateUsingClause(code, "");
		//        string o2 = Global.BusinessRuleCompiler.AddMethodRegion(o1, Global.CurrentUser.OrganizationID.ToString());
		//        string DllCode = Global.BusinessRuleCompiler.UpdateMethods(o2, method, rule.GetMethodInnerCode());
		//        CompileResult actCompilation = Global.BusinessRuleCompiler.CompileCodeFile(DllCode);
		//        if ( actCompilation.status ) {
		//            Debug.WriteLine("Rule Validation successful");
		//            ok = true;
		//        } else {
		//            string error = "";
		//            for ( int i = 0; i < actCompilation.CSharpResults.Errors.Count; i++ ) {
		//                error += actCompilation.CSharpResults.Errors[i].ErrorText + Environment.NewLine;
		//            }
		//            MessageBox.Show(error, this.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
		//            ok = false;
		//        }
		//    } catch ( Exception ) {
		//        ok = false;
		//    }
		//    return ok;
		//}		
		#endregion

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <returns></returns>
		public override DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew)
		{
			FormCreateNewRule dlgNew = new FormCreateNewRule(this, this, bAllowContinue);
			dlgNew.DomainID = idDomain;
			dlgNew.ShowAllFolders = false;
			dlgNew.ParentItem = parentItem;
			DialogResult result = dlgNew.ShowDialog();
			if ( result == DialogResult.OK || result == DialogResult.Retry ) {
				idDomain = dlgNew.DomainID;
				parentItemNew = dlgNew.NewParentItem;
			} else {
				idDomain = 0;
				parentItemNew = null;
			}
			return result;
		}

		/// <summary>
		/// Gets the policy.
		/// </summary>
		/// <returns></returns>
		public BusinessPolicy GetPolicy()
		{
			BusinessPolicy policy = null;
			DataTable dt = Global.Data.GetRepositoryHierarchyParents(this);
			if ( dt != null && dt.Rows.Count > 0 ) {
				foreach ( DataRow row in dt.Rows ) {
					if ( (int)row["parent_reptype_id"] == (int)ItemType.BPolicy ) {
						policy = this.RepositoryService.GetItem<BusinessPolicy>((int)row["parent_id"]);
						if ( policy != null )
							break;
					}
				}
			}
			return policy;
		}

		/// <summary>
		/// Gets the rule parameter resolve list.
		/// </summary>
		/// <returns></returns>
		public BindingListEx<Workflow.RuleParameterResolve> GetRuleParameterResolveList()
		{
			BindingListEx<Workflow.RuleParameterResolve> lst = new BindingListEx<Workflow.RuleParameterResolve>();
			foreach ( var item in this.ExtendedProperties.Conditions ) {
				if ( item.LeftNounID > 0 ) {
					if ( existsNounInResolveList(lst, item.LeftNounID) ) {
						continue;
					}
					Workflow.RuleParameterResolve r1 = new Workflow.RuleParameterResolve();
					r1.ParameterDataType = item.LeftDataTypeString;
					r1.ParameterID = item.LeftNounID;
					r1.ParameterName = item.LeftValueString;
					r1.ParameterResolve = "";
					lst.Add(r1);
				} else if ( item.LeftRuleID > 0 ) {
					RepositoryBusinessRule br1 = this.RepositoryService.GetItem<RepositoryBusinessRule>(item.LeftRuleID);
					if ( br1 != null && br1 != this ) {
						BindingListEx<Workflow.RuleParameterResolve> lst1 = br1.GetRuleParameterResolveList();
						foreach ( var item1 in lst1 ) {
							if ( !existsNounInResolveList(lst, item1.ParameterID) ) {
								lst.Add(item1);
							}
						}
					}
				}
				if ( item.RightNounID > 0 ) {
					if ( existsNounInResolveList(lst, item.RightNounID) ) {
						continue;
					}
					Workflow.RuleParameterResolve r2 = new Workflow.RuleParameterResolve();
					r2.ParameterDataType = item.RightDataTypeString;
					r2.ParameterID = item.RightNounID;
					r2.ParameterName = item.RightValueString;
					r2.ParameterResolve = "";
					lst.Add(r2);
				} else if ( item.RightRuleID > 0 ) {
					RepositoryBusinessRule br2 = this.RepositoryService.GetItem<RepositoryBusinessRule>(item.RightRuleID);
					if ( br2 != null && br2 != this ) {
						BindingListEx<Workflow.RuleParameterResolve> lst2 = br2.GetRuleParameterResolveList();
						foreach ( var item2 in lst2 ) {
							if ( !existsNounInResolveList(lst, item2.ParameterID) ) {
								lst.Add(item2);
							}
						}
					}
				}
			}
			return lst;
		}

		private static bool existsNounInResolveList(BindingListEx<Workflow.RuleParameterResolve> lst, int id)
		{
			return lst.Exists(delegate(Workflow.RuleParameterResolve rpr)
			{
				return ( rpr.ParameterID == id );
			});
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public override IRepositoryItem Copy(bool deep)
		{
			RepositoryBusinessRule copy = new RepositoryBusinessRule(true);
			copy.InitializeServiceProvider(this);
			this.CopyDataRowToTarget(copy);
			return copy;
		}
		#endregion

		#region Variables
		//private OpenComposite.Base.BusinessRule _brule;
		private List<int> _listRuleConsts = null;
		private List<int> _listUsedNouns = null;
		#endregion

		#region Class: BusinessRuleProperties
		[Serializable]
		[XmlRoot(Namespace = "http://www.OpenComposite.com/Repository")]
		[XmlType(Namespace = "http://www.OpenComposite.com/Repository")]
		public class BusinessRuleProperties
		{
			/// <summary>
			/// Initializes a new instance of the <see cref="BusinessRuleProperties"/> class.
			/// </summary>
			public BusinessRuleProperties()
			{
				_ruletype = BusinessRuleType.GenericRule;
			}

			private BusinessRuleType _ruletype;
			/// <summary>
			/// Gets or sets the type of the rule.
			/// </summary>
			/// <value>The type of the rule.</value>
			public BusinessRuleType RuleType
			{
				get { return _ruletype; }
				set { _ruletype = value; }
			}

			private List<IFSymbol.Condition> _conditions = new List<IFSymbol.Condition>();
			/// <summary>
			/// Gets the conditions.
			/// </summary>
			/// <value>The conditions.</value>
			[XmlIgnore]
			public List<IFSymbol.Condition> Conditions
			{
				get { return _conditions; }
			}
			/// <summary>
			/// Gets or sets the conditions array.
			/// </summary>
			/// <value>The conditions array.</value>
			[EditorBrowsable(EditorBrowsableState.Never)]
			[XmlArray("Conditions")]
			public IFSymbol.Condition[] ConditionsArray
			{
				get { return _conditions.ToArray(); }
				set { _conditions = new List<IFSymbol.Condition>(value); }
			}

			private int _workflowID;
			/// <summary>
			/// Gets or sets the workflow ID.
			/// </summary>
			/// <value>The workflow ID.</value>
			public int WorkflowID
			{
				get { return _workflowID; }
				set { _workflowID = value; }
			}

		}
		#endregion

		#region Enum: BusinessRuleType
		[XmlType(Namespace = "http://www.OpenComposite.com/Repository")]
		public enum BusinessRuleType
		{
			GenericRule = 0,
			ParticipantRule = 1
		}
		#endregion

		#region IParticipant Members

		/// <summary>
		/// Gets the type of the participant.
		/// </summary>
		/// <value>The type of the participant.</value>
		public ParticipantType ParticipantType
		{
			get
			{
				if ( this.ExtendedProperties.RuleType == BusinessRuleType.ParticipantRule ) {
					return ParticipantType.ParticipantRule;
				}
				return ParticipantType.None;
			}
		}

		#endregion

		#region IEquatable<IParticipant> Members

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		public bool Equals(IParticipant other)
		{
			RepositoryBusinessRule otherrule = other as RepositoryBusinessRule;
			if ( otherrule != null ) {
				return ( otherrule.ID == this.ID );
			}
			return false;
		}

		#endregion
	}
}
